<?php

namespace app\hooks;

use app\api\model\ModeOneLevel;
use app\api\model\ModeOrders;
use app\api\model\User;
use think\facade\Db;
use think\facade\Log;

class ModeOneHook
{
    public const RATE_OF_STATIC = 8;
    public const RATE_OF_298 = 180;
    public const RATE_OF_DIRECT = 20;
    public const RATE_OF_BALANCE = 80;
    public const RATE_OF_FEE = 10;
    public const RATE_OF_INTEGRAL = 10;


    public static function paid_run($order_id)
    {
        if ($order_info = ModeOrders::where('id', $order_id)->whereIn('type', [1, 2])->findOrEmpty()->toArray()) {

            $user_info = User::findOrEmpty((int)$order_info['user_id'])->toArray();

            $achievements = ['padian' => []];

            if ($parent_users = ModeHook::getUserParents((int)$user_info['pid'])) {

                $current_padian_rate = 0;

                foreach ($parent_users as $parent_user) {

                    if ($parent_user['padian_rate'] > 0 && $parent_user['padian_rate'] > $current_padian_rate) {

                        $rate = (float)$parent_user['padian_rate'] - $current_padian_rate;

                        $padian_amount = ModeHook::computePercentAmount($order_info['principal'], $rate);

                        $achievements['padian'][$parent_user['id']] = $padian_amount;

                        self::deductionFirstReleasableOrder($order_id, $parent_user['id'], $padian_amount, 'speedup', 'padian');

                        $current_padian_rate = (float)$parent_user['padian_rate'];
                    }
                }
            }

            ModeOrders::where('id', $order_info['id'])->update(['active_achievements' => json_encode($achievements), 'last_achievements_time' => time()]);
        }
        return true;
    }

    public static function static_run()
    {

        ModeOrders::where('is_delete', 0)->whereIn('type', [1, 2])->where('status', 'payed')->whereNotNull('pay_time')->update(['achievements' => '', 'last_achievements_time' => 0]);

        if ($orders = ModeOrders::where('is_delete', 0)->whereIn('type', [1, 2])->where('status', 'payed')->whereNotNull('pay_time')->where('remain_earnings', '>', 0)->order('pay_time', 'asc')->select()) {

            $release_type_percent = [1 => self::RATE_OF_STATIC, 2 => self::RATE_OF_298];

            $levels = ModeOneLevel::field(implode(', ', ['id', 'name', 'rate', 'equality_rate']))->order('id', 'asc')->select()->toArray();

            $levels = array_column($levels, null, 'id');
            $levels[0] = ['id' => 0, 'name' => '游客', 'rate' => 0, 'equality_rate' => 0];
            sort($levels);


            foreach ($orders as $ok => $order) {

                $order = $order->toArray();

                $user_info = User::findOrEmpty((int)$order['user_id'])->toArray();

                $achievements = ['static' => ModeHook::computePercentAmount($order['principal'], $release_type_percent[(int)$order['type']], 1000), 'jicha' => [], 'pingji' => [], 'direct' => []];

                if ($parent_users = ModeHook::getUserParents((int)$user_info['pid'])) {

                    $direct_parent_user = $parent_users[0];

                    $achievements['direct'][$direct_parent_user['id']] = ModeHook::computePercentAmount($achievements['static'], self::RATE_OF_DIRECT);

                    $current_user_level_rate = (float)$levels[($current_user_level_id = $user_info['mode_one_level_id'])]['rate'];

                    foreach ($parent_users as $pk => $parent_user) {

                        if ((int)$parent_user['mode_one_level_id'] > $current_user_level_id) {

                            $rate = (float)$levels[(int)$parent_user['mode_one_level_id']]['rate'] - $current_user_level_rate;

                            $jicha_amount = ModeHook::computePercentAmount($achievements['static'], $rate);

                            $achievements['jicha'][(int)$parent_user['mode_one_level_id']][(int)$parent_user['id']] = $jicha_amount;

                            $current_user_level_rate = (float)$levels[($current_user_level_id = (int)$parent_user['mode_one_level_id'])]['rate'];

                        }

                    }

                    foreach ($levels as $level) {

                        if ($level['id'] <= (int)$user_info['mode_one_level_id'] || !isset($achievements['jicha'][(int)$level['id']])) {
                            continue;
                        }

                        foreach ($parent_users as $pk => $parent_user) {

                            //判断等级是否足够
                            if ((int)$parent_user['mode_one_level_id'] === (int)$level['id'] && !isset($achievements['jicha'][(int)$level['id']][(int)$parent_user['id']])) {

                                $achievements['pingji'][$level['id']][$parent_user['id']] = ModeHook::computePercentAmount($achievements['static'], (float)$level['equality_rate']);

                                //跳出循环
                                break;
                            }

                        }

                    }
                }

                $orders[$ok] = $order = array_merge($order, compact('achievements'));

                ModeOrders::where('id', $order['id'])->update(['achievements' => json_encode($achievements), 'last_achievements_time' => time()]);

                $release = self::release($order, $achievements);

                unset($orders[$ok], $achievements, $release);
            }
        }
        return true;
    }

    private static function release($order_info, $achievements)
    {
        foreach ($achievements as $speedup_type => $amounts) {
            if ($amounts) {
                switch ($speedup_type) {
                    case 'static':
                        self::deductionFirstReleasableOrder($order_info['id'], $order_info['user_id'], (int)$amounts, 'mode_static_release', '');
                        break;
                    case 'direct':
                        foreach ($amounts as $user_id => $amount) {
                            self::deductionFirstReleasableOrder($order_info['id'], $user_id, $amount, 'speedup', 'direct');
                        }
                        break;
                    default:
                        foreach ($amounts as $level_id => $level_amounts) {
                            foreach ($level_amounts as $user_id => $amount) {
                                self::deductionFirstReleasableOrder($order_info['id'], $user_id, $amount, 'speedup', $speedup_type);
                            }
                        }
                        break;
                }
            }
        }
        return true;

    }

    private static function deductionFirstReleasableOrder($from_order_id, $user_id, $total_amount, $type, $speedup_type)
    {

        if ($first_releasable_order = ModeOrders::where('is_delete', 0)->whereIn('type', [1, 2])->where('user_id', $user_id)->where('status', 'payed')->whereNotNull('pay_time')->where('remain_earnings', '>', 0)->order('pay_time', 'asc')->findOrEmpty()->toArray()) {

            if ($current_release_amount = min($total_amount, $first_releasable_order['remain_earnings'])) {

                self::releaseAction($user_id, $current_release_amount, $from_order_id, $first_releasable_order['id'], $type, $speedup_type);

                if (($order_surplus_amount = $total_amount - $current_release_amount) > 0) {

                    return self::deductionFirstReleasableOrder($from_order_id, $user_id, $order_surplus_amount, $type, $speedup_type);

                }
            }

        }
        return true;
    }

    private static function releaseAction($user_id, $amount, $from_order_id, $release_order_id, $type, $speedup_type)
    {
        if ($amount <= 0) {
            return true;
        }

        Db::startTrans();

        try {

            $log_content = ModeHook::orderRelease($release_order_id, $amount, $from_order_id, $type, $speedup_type);

            $balance = ModeHook::computePercentAmount($amount, self::RATE_OF_BALANCE);
            $fee = ModeHook::computePercentAmount($amount, self::RATE_OF_FEE);
            $integral = $amount - $balance - $fee;

            ModeHook::createIncome($user_id, $balance, $integral, $amount, 'green_points', $type, $log_content);

            Db::commit();
        } catch (\Exception $exception) {

            Db::rollback();

            Log::error('ModeOneOrderRelease:'.json_encode(['message' => $exception->getMessage(), 'file' => $exception->getFile(), 'line' => $exception->getLine()], JSON_UNESCAPED_UNICODE));
        }

        return true;
    }


}